#ifndef CLIENT_H
#define CLIENT_H

#include <cstdlib>
#include <deque>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

#include "favorite.pb.h"
#include "message.h"

using boost::asio::ip::tcp;
typedef void (*RxMsg_ptr)(Message & inMsg) ;

class Client : public boost::enable_shared_from_this<Client>
{
public:
    Client(boost::asio::io_service& io_service,
           tcp::resolver::iterator endpoint_iterator,
           RxMsg_ptr inRxMsgPtr) ;

    void write(const Message & msg) ;
    void read ( ) ;
    void close() ;
    Message getInMsg() ;

private:

    void handle_connect(const boost::system::error_code& error,
                        tcp::resolver::iterator endpoint_iterator) ;
    void do_read() ;
    void handle_read_header(const boost::system::error_code& error) ;
    void handle_read_body(const boost::system::error_code& error) ;
    void do_write(const Message & outMsg) ;
    void handle_write(const boost::system::error_code& error) ;
    void do_close() ;

private:
    boost::asio::io_service& io_service_;
    /// Strand to ensure the connection's handlers are not called concurrently.
    boost::asio::io_service::strand strand_;
    tcp::socket socket_;
    Message inMsg;
    RxMsg_ptr RxMsg ;
};

typedef boost::shared_ptr<Client> ClientPtr ;

#endif
